package com.c5p1ng.activiti.sample.controller;

import com.c5p1ng.activiti.sample.vo.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

/**
 * TODO
 *
 * @author csp
 **/
@Slf4j
@RestController("/engine")
@Tag(name = "引擎管理")
public class EngineController {
    @Resource
    private RepositoryService repositoryService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    @Resource
    private HistoryService historyService;

    @Operation(summary = "zip部署流程")
    @PostMapping("/deploy")
    public R deploy(@RequestPart("file")MultipartFile file) {
        try {
            if(file.isEmpty()) {
                throw new NullPointerException("部署压缩包不能为空");
            }
            DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
            ZipInputStream zip = new ZipInputStream(file.getInputStream());
            deploymentBuilder.addZipInputStream(zip);
            //设置部署流程名称
            deploymentBuilder.name("请假审批");
            //部署流程
            Deployment deploy = deploymentBuilder.deploy();
            return R.ok(deploy.getId());
        } catch (Exception e) {
            log.error("部署异常：", e);
            return R.failed(e.toString());
        }
    }

    @Operation(summary = "查询流程部署信息")
    @GetMapping("/queryDeploymentInfo")
    public R queryDeploymentInfo() {
        List<Deployment> list = repositoryService.createDeploymentQuery().list();
        log.info("流程部署信息： {}", list.toString());
        return R.ok(list.toString());
    }

    @Operation(summary = "查询流程定义信息")
    @GetMapping("/queryProcessInfo")
    public R queryProcessInfo() {
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
        log.info("流程定义信息： {}", list.toString());
        return R.ok(list.toString());
    }

    @Operation(summary = "根据部署id删除流程部署")
    @GetMapping("/deleteDeploymentById")
    public R deleteDeploymentById(@Parameter(description = "流程部署id", required = true) String deploymentId) {
        List<Deployment> list = repositoryService.createDeploymentQuery().deploymentId(deploymentId).list();
        if(CollectionUtils.isEmpty(list) || list.size() != 1) {
            return R.failed("流程定义未找到");
        }
        repositoryService.deleteDeployment(deploymentId);
        return R.ok("删除成功");
    }

    @Operation(summary = "发起流程")
    @GetMapping("/startProcess")
    public R startProcess(@Parameter(description = "流程定义id", required = true) String processDefinitionId,
                          @Parameter(description = "经办人", required = true) String userName) {
        log.info("发起流程，processDefinitionId：{}", processDefinitionId);
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).list();
        if(CollectionUtils.isEmpty(list) || list.size() != 1) {
            return R.failed("流程定义不存在");
        }
        Map<String, Object> variable = new HashMap<>();
        variable.put("userName", userName);
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, variable);
        log.info("流程实例：{}", processInstance.toString());
        return R.ok("发起成功");
    }

    @Operation(summary = "完成任务")
    @GetMapping("/completeTask")
    public R completeTask(@Parameter(description = "流程实例id", required = true) String processInstanceId) {
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        if(CollectionUtils.isEmpty(list) || list.size() != 1) {
            return R.failed("当前没有任务");
        }
        log.info("任务列表：{}", list);
        taskService.complete(list.get(0).getId());

        return R.ok("完成任务");
    }

    @Operation(summary = "查询历史流程实例")
    @GetMapping("/queryHistoryProcessInstance")
    public R queryHistoryProcessInstance() {
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().list();
        log.info("查询历史流程实例：{}", list.toString());
        return R.ok(list.toString());
    }

    @Operation(summary = "查询历史任务")
    @GetMapping("/queryHistoryTask")
    public R queryHistoryTask() {
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().list();
        log.info("查询历史任务：{}", list.toString());
        return R.ok(list.toString());
    }

    @Operation(summary = "查看历史活动流程实例")
    @GetMapping("/queryActivityInstance")
    public R queryActivityInstance() {
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().list();
        log.info("查看历史活动流程实例：{}", list.toString());
        return R.ok(list.toString());
    }

    @Operation(summary = "根据代办人查询任务")
    @GetMapping("/queryByAssigneeTask")
    public R queryByAssigneeTask(@Parameter(description = "代办人", required = true) String assignee) {
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee(assignee)
                .active()
                .list();
        log.info("根据代办人查询任务：{}", list.toString());
        return R.ok(list.toString());
    }

    @Operation(summary = "按任务id更新代办人")
    @GetMapping("/updateAssigneeByTaskId")
    public R updateAssigneeByTaskId(@Parameter(description = "任务id", required = true) String taskId,
                                    @Parameter(description = "代办人", required = true) String assignee) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if(task == null) {
            return R.failed("任务不存在");
        }
        taskService.setAssignee(taskId, assignee);
        return R.ok("更新成功");
    }

    @Operation(summary = "添加审批人意见")
    @GetMapping("/addComment")
    public R addComment(@Parameter(description = "任务id", required = true) String taskId,
                        @Parameter(description = "流程实例id", required = true) String processInstanceId,
                        @Parameter(description = "意见内容", required = true) String message) {
        Task task = taskService.createTaskQuery().taskId(taskId).processInstanceId(processInstanceId).singleResult();
        if(task == null) {
            return R.failed("任务不存在");
        }
        taskService.addComment(taskId, processInstanceId, message);
        return R.ok("添加成功");
    }

    @Operation(summary = "查询个人审批意见")
    @GetMapping("/queryComment")
    public R queryComment(@Parameter(description = "任务id", required = true) String taskId) {
        List<Comment> taskComments = taskService.getTaskComments(taskId);
        log.info("查询个人审批意见：{}", taskComments.toString());
        return R.ok(taskComments.toString());
    }

    @Operation(summary = "根据候选人查询任务")
    @GetMapping("/queryTaskByCandidateUser")
    public R queryTaskByCandidateUser(@Parameter(description = "候选人名称", required = true) String userName) {
        List<Task> list = taskService.createTaskQuery().taskCandidateUser(userName).list();
        log.info("查询个人审批意见：{}", list.toString());
        return R.ok(list);
    }

    @Operation(summary = "拾取任务，拾取后的任务，该候选人才可以完成任务")
    @GetMapping("/claimTask")
    public R claimTask(@Parameter(description = "任务id", required = true) String taskId,
                       @Parameter(description = "候选人名称", required = true) String userName) {
        Task task = taskService.createTaskQuery().taskId(taskId).taskCandidateUser(userName).singleResult();
        if(task == null) {
            return R.failed("任务不存在");
        }
        taskService.claim(taskId, userName);
        return R.ok("拾取任务成功");
    }
}
